﻿using Microsoft.SqlServer.Server;
using SketchUpAPI.NET.Enums;
using SketchUpAPI.NET.SketchUp.Exception;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;

namespace SketchUpAPI.NET.Objects
{
    /// <summary>
    /// 平面，该平面由一个平面方程描述：ax + by + cz + d = 0，且系数已经归一化，使得 a*a + b*b + c*c = 1
    /// </summary>
    /// <remarks>默认状态下表示 WorldXY</remarks>
    [StructLayout(LayoutKind.Sequential, Pack = 8)]
    public struct Plane3D
    {
        #region API 函数
        /// <summary>
        /// 三点创建平面
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="point3"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DSetWithPoints(ref Plane3D plane, Point3D point1, Point3D point2, Point3D point3);

        /// <summary>
        /// 原点和法向创建平面
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="point"></param>
        /// <param name="normal"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DSetWithPointAndNormal(ref Plane3D plane, Point3D point, Vector3D normal);

        /// <summary>
        /// 使用平面方程创建一个平面
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DSetWithCoefficients(ref Plane3D plane, double a, double b, double c, double d);

        /// <summary>
        /// 获取原点
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="position"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DGetPosition(Plane3D plane, ref Point3D position);

        /// <summary>
        /// 获取平面的法向
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="normal"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DGetNormal(Plane3D plane, ref Vector3D normal);

        /// <summary>
        /// 判断点是否在平面上
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="point"></param>
        /// <param name="is_on"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DIsOn(Plane3D plane, Point3D point, out bool is_on);

        /// <summary>
        /// 计算点与平面的距离
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="point"></param>
        /// <param name="distance"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DDistanceTo(Plane3D plane, Point3D point, out double distance);

        /// <summary>
        /// 将点投影到平面上
        /// </summary>
        /// <param name="plane"></param>
        /// <param name="point"></param>
        /// <param name="projected_point"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DProjectTo(Plane3D plane, Point3D point, ref Point3D projected_point);

        /// <summary>
        /// 将变换应用到平面上
        /// </summary>
        /// <param name="transform"></param>
        /// <param name="plane"></param>
        /// <returns></returns>
        [DllImport(ObjectBase.LIB)]
        static extern SUResult SUPlane3DTransform(Transformation transform, ref Plane3D plane);
        #endregion

        public double a;
        public double b;
        public double c;
        public double d;

        /// <summary>
        /// 原点
        /// </summary>
        public Point3D Origin
        {
            get
            {
                Point3D p = Point3D.Origin;
                SketchUpExceptionHelper.ThrowSUResult(SUPlane3DGetPosition(this, ref p));
                return p;
            }
        }

        /// <summary>
        /// 法向
        /// </summary>
        public Vector3D Normal
        {
            get
            {
                Vector3D v = new Vector3D();
                SketchUpExceptionHelper.ThrowSUResult(SUPlane3DGetNormal(this, ref v));
                return v;
            }
        }

        /// <summary>
        /// 使用三点创建一个平面
        /// </summary>
        /// <param name="point1"></param>
        /// <param name="point2"></param>
        /// <param name="point3"></param>
        /// <returns></returns>
        public static Plane3D Create(Point3D point1, Point3D point2, Point3D point3)
        {
            Plane3D p = new Plane3D();
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DSetWithPoints(ref p, point1, point2, point3));
            return p;
        }

        /// <summary>
        /// 使用原点和法向创建平面
        /// </summary>
        /// <param name="origin"></param>
        /// <param name="normal"></param>
        /// <returns></returns>
        public static Plane3D Create(Point3D origin, Vector3D normal)
        {
            Plane3D p = new Plane3D();
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DSetWithPointAndNormal(ref p, origin, normal));
            return p;
        }

        /// <summary>
        /// 使用平面方程创建一个平面
        /// </summary>
        /// <remarks>平面方程：ax + by + cz + d = 0</remarks>
        /// <param name="a"></param>
        /// <param name="b"></param>
        /// <param name="c"></param>
        /// <param name="d"></param>
        /// <returns></returns>
        public static Plane3D Create(double a, double b, double c, double d)
        {
            Plane3D p = new Plane3D();
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DSetWithCoefficients(ref p, a, b, c, d));
            return p;
        }

        /// <summary>
        /// 点是否在平面上
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public bool IsOnPlane(Point3D point)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DIsOn(this, point, out bool isOn));
            return isOn;
        }

        /// <summary>
        /// 点到平面的距离
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public double DistanceTo(Point3D point)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DDistanceTo(this, point, out double distance));
            return distance;
        }

        /// <summary>
        /// 将点投影到平面上
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public Point3D Project(Point3D point)
        {
            Point3D p = new Point3D();
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DProjectTo(this, point, ref p));
            return p;
        }

        /// <summary>
        /// 将点关于该平面镜像
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        public Point3D Mirror(Point3D point)
        {
            /* 将一个点关于一个平面镜像
             * 1、首先将该点投影到平面上
             * 2、那么该投影点就是 点与镜像点连线的中点
             */

            Point3D pro = Project(point);
            return -point + pro * 2;
        }

        /// <summary>
        /// 将变换应用到平面
        /// </summary>
        /// <param name="transform"></param>
        public void Apply(Transformation transform)
        {
            SketchUpExceptionHelper.ThrowSUResult(SUPlane3DTransform(transform, ref this));
        }
    }
}